import axios, { AxiosError } from 'axios';
import requestCancel from './module/requestCancel';
import refreshToken from './module/refreshToken';
import { useTokenStore } from '@/stores/login/useTokenStore';
import { responseError } from './module/responseError';
import { responseIsAxiosApiResponse } from './helper/response';
import { useLoginStore } from '@/stores/login';
import CryptoSm4js from '../cryptoSm4js';

const crypto = new CryptoSm4js();

/** 实例配置类型 */
type InstanceConfig = NonNullable<Parameters<typeof axios.create>[0]>;

/**
 *
 * 创建axios实例
 */
export function createAxiosInstance(config?: InstanceConfig) {
  const instance = axios.create(config);
  const is_env_crypt = import.meta.env.VITE_API_CRYPT === 'true';

  instance.interceptors.request.use(
    config => {
      const tokenStore = useTokenStore();

      /**
       * 接口访问需要有效的身份授权
       */
      if (!config.option?.withoutAuth) {
        // 是否有效的身份授权（token未过期或可刷新）
        if (tokenStore.isValidAuth === false) {
          throw new AxiosError('接口需要授权后访问，当前请求已终止', 'ERR_REQUIRED_AUTH', config);
        }
      }

      /**
       * 重复请求处理
       */
      // if (!config.option?.closeRepeatCancel) {
      //   requestCancel.handleRequest(config);
      // }

      /**
       * 设置超时配置
       */
      const timeout = config.option?.timeout ?? 0;
      if (timeout > 0) {
        config.timeout = timeout;
      }

      /**
       * 设置token
       */
      if (!config.option?.withoutToken) {
        config.headers.Authorization = tokenStore.accessToken;
      }

      /**
       * 加密
       */
      if (is_env_crypt && !config.option?.noEncrypt) {
        // todo: 加密
        if (config.params) {
          console.log(config.url + ' config.params', config.params);
          // @ts-ignore
          config.params = { req_params: crypto.encrypt(config.params) };
        }
        if (config.data) {
          // @ts-ignore
          console.log(config.url + ' config.data', config.data);
          config.data = { req_data: crypto.encrypt(config.data) };
        }
      }

      /**
       * 刷新token
       */
      if (
        !config.option?.withoutToken &&
        tokenStore.canRefresh &&
        config.url !== '/v7/auth/login/refresh-token'
      ) {
        return new Promise<typeof config>(resolve => {
          refreshToken.pushResolveFn(() => {
            config.headers.Authorization = tokenStore.accessToken;
            resolve(config);
          });
        });
      }

      return config;
    },
    err => {
      // 请求错误，如请求配置中的验证等，暂时用不到
      console.log('请求错误：', err);
      return Promise.reject(err);
    },
  );

  instance.interceptors.response.use(
    response => {
      /**
       * 解密
       */
      if (is_env_crypt && !response.config.option?.noDecrypt) {
        // todo: 解密
        try {
          response.data = JSON.parse(crypto.decrypt(response.data));
        } catch (e) {
          /* empty */
        }
        console.log(response.config.url + ' response.data ', response.data);
        // console.log('解密后信息', { ...response.config });
      }

      /**
       * 重复请求处理
       */
      if (!response.config.option?.closeRepeatCancel) {
        requestCancel.handleResponse(response);
      }

      if (responseIsAxiosApiResponse(response)) {
        /** 响应提示消息 */
        responseError(response);

        /** 后端响应数据结构中，success为false时, 返回 rejected promise */
        if (!response.data.success) {
          return Promise.reject(response);
        }
      }

      return response;
    },
    err => {
      console.log('err:', err);
      /**
       * 处理请求拦截抛出的错误，http 状态码错误
       * 响应拦截中手动抛出的错误此处捕获不到
       */

      // 基于AxiosError类型的错误
      if (err instanceof AxiosError) {
        switch (err.code) {
          case 'ERR_CANCELED':
            // 请求被取消处理
            break;
          case 'ERR_REFRESH_TOKEN':
            // 刷新token失败
            useLoginStore().logout();
            break;
          case 'ERR_REQUIRED_AUTH':
            // 必须授权后访问，仅对开发人员提示
            console.log(err);
            break;
          default:
            console.log('响应错误：', err);
        }
      }
      return Promise.reject(err);
    },
  );
  return instance;
}
